package endian

/*
 * @Author: Wangjun
 * @Date: 2023-06-06 14:40:23
 * @LastEditTime: 2025-02-12 13:52:42
 * @LastEditors: wangjun haodreams@163.com
 * @Description:
 * @FilePath: \libs\easy\binary.go
 * hnxr
 */

import (
	"encoding/binary"
	"fmt"
	"math"
)

type Endian int

const (
	LittleEndian Endian = iota
	BigEndian
)

// int uint 不同的硬件 字节长度不一致，因此不支持
func (m Endian) Encode(b []byte, vs ...any) (pos int, err error) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}
	for i, v := range vs {
		switch val := v.(type) {
		case float64:
			e.PutUint64(b[pos:], math.Float64bits(val))
			pos += 8
		case float32:
			e.PutUint32(b[pos:], math.Float32bits(val))
			pos += 4
		case int8:
			b[pos] = byte(val)
			pos++
		case int16:
			e.PutUint16(b[pos:], uint16(val))
			pos += 2
		case int32:
			e.PutUint32(b[pos:], uint32(val))
			pos += 4
		case int64:
			e.PutUint64(b[pos:], uint64(val))
			pos += 8
		case byte:
			b[pos] = val
			pos++
		case uint16:
			e.PutUint16(b[pos:], val)
			pos += 2
		case uint32:
			e.PutUint32(b[pos:], val)
			pos += 4
		case uint64:
			e.PutUint64(b[pos:], val)
			pos += 8
		case string:
			pos += copy(b[pos:], []byte(val))
		case []byte:
			pos += copy(b[pos:], val)
		case *float64:
			if val != nil {
				e.PutUint64(b[pos:], math.Float64bits(*val))
			}
			pos += 8
		case *float32:
			if val != nil {
				e.PutUint32(b[pos:], math.Float32bits(*val))
			}
			pos += 4
		case *int8:
			if val != nil {
				b[pos] = byte(*val)
			}
			pos++
		case *int16:
			if val != nil {
				e.PutUint16(b[pos:], uint16(*val))
			}
			pos += 2
		case *int32:
			if val != nil {
				e.PutUint32(b[pos:], uint32(*val))
			}
			pos += 4
		case *int64:
			if val != nil {
				e.PutUint64(b[pos:], uint64(*val))
			}
			pos += 8
		case *byte:
			if val != nil {
				b[pos] = *val
			}
			pos++
		case *uint16:
			if val != nil {
				e.PutUint16(b[pos:], *val)
			}
			pos += 2
		case *uint32:
			if val != nil {
				e.PutUint32(b[pos:], *val)
			}
			pos += 4
		case *uint64:
			if val != nil {
				e.PutUint64(b[pos:], *val)
			}
			pos += 8
		case *string:
			if val == nil {
				err = fmt.Errorf("param [%d] error, null ptr", i+1)
				return
			}
			pos += copy(b[pos:], []byte(*val))
		case *[]byte:
			if val == nil {
				err = fmt.Errorf("param [%d] error, null ptr", i+1)
				return
			}
			pos += copy(b[pos:], *val)
		case int, uint, *int, *uint:
			err = fmt.Errorf("param [%d] type of int|uint not support", i+1)
			return
		default:
			err = fmt.Errorf("param [%d] error", i+1)
			return
		}
	}
	return
}

// vs 必须是指针
func (m Endian) Decode(b []byte, vs ...any) (pos int, err error) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	for i, v := range vs {
		switch val := v.(type) {
		case *float64:
			if val != nil {
				*val = math.Float64frombits(e.Uint64(b[pos:]))
			}
			pos += 8
		case *float32:
			if val != nil {
				*val = math.Float32frombits(e.Uint32(b[pos:]))
			}
			pos += 4
		case *int8:
			if val != nil {
				*val = int8(b[pos])
			}
			pos++
		case *int16:
			if val != nil {
				*val = int16(e.Uint16(b[pos:]))
			}
			pos += 2
		case *int32:
			if val != nil {
				*val = int32(e.Uint32(b[pos:]))
			}
			pos += 4
		case *int64:
			if val != nil {
				*val = int64(e.Uint64(b[pos:]))
			}
			pos += 8
		case *byte:
			if val != nil {
				*val = b[pos]
			}
			pos++
		case *uint16:
			if val != nil {
				*val = e.Uint16(b[pos:])
			}
			pos += 2
		case *uint32:
			if val != nil {
				*val = e.Uint32(b[pos:])
			}
			pos += 4
		case *uint64:
			if val != nil {
				*val = e.Uint64(b[pos:])
			}
			pos += 8
		case int, uint, *int, *uint, *string, *[]byte:
			err = fmt.Errorf("param [%d] type of int|uint|string|[]byte not support", i+1)
			return
		default:
			err = fmt.Errorf("param [%d] error", i+1)
			return
		}
	}
	return
}

func (m Endian) Float32(b []byte) (f float32, pos int) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	f = math.Float32frombits(e.Uint32(b))
	pos += 4
	return
}

func (m Endian) Float64(b []byte) (f float64, pos int) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	f = math.Float64frombits(e.Uint64(b))
	pos += 8
	return
}

func (m Endian) PutFloat32(b []byte, f float32) (pos int) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	e.PutUint32(b, math.Float32bits(f))
	pos += 4
	return
}

func (m Endian) PutFloat64(b []byte, f float64) (pos int) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	e.PutUint64(b, math.Float64bits(f))
	pos += 8
	return
}

// 连续读取数据
func (m Endian) Unit16(b []byte, count int) (array []uint16, pos int) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	array = make([]uint16, count)
	for i := 0; i < count; i++ {
		array[i] = e.Uint16(b[pos:])
		pos += 2
	}
	return
}

// 连续存放数据
func (m Endian) PutUint16(b []byte, vs ...uint16) int {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	pos := 0
	for _, v := range vs {
		e.PutUint16(b[pos:], v)
		pos += 2
	}
	return pos
}

// 连续读取数据
func (m Endian) Unit32(b []byte, count int) (array []uint32, pos int) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	array = make([]uint32, count)
	for i := 0; i < count; i++ {
		array[i] = e.Uint32(b[pos:])
		pos += 4
	}
	return
}

// 连续存放数据
func (m Endian) PutUint32(b []byte, vs ...uint32) int {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	pos := 0
	for _, v := range vs {
		e.PutUint32(b[pos:], v)
		pos += 4
	}
	return pos
}

// 连续读取数据
func (m Endian) Unit64(b []byte, count int) (array []uint64, pos int) {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	array = make([]uint64, count)
	for i := 0; i < count; i++ {
		array[i] = e.Uint64(b[pos:])
		pos += 8
	}
	return
}

// 连续存放数据
func (m Endian) PutUint64(b []byte, vs ...uint64) int {
	var e binary.ByteOrder = binary.BigEndian
	if m == 0 {
		e = binary.LittleEndian
	}

	pos := 0
	for _, v := range vs {
		e.PutUint64(b[pos:], v)
		pos += 8
	}
	return pos
}
